#!/usr/bin/env python2

import os
import errno
import json
from paramiko import SSHException

from config import Config
from node import Node
from utils import _dwarn, _derror, Exp, mutil_exec, _exec_remote, _set_value

def _str(lst):
    s = ""
    for i in lst:
        s = s + str(i) + ','
    return s[:-1]

class Gemini:
    def __listnode(self, k):
        cmd = "%s --stat --json" % (self.node_script)
        try:
            (out, err) = _exec_remote(k, cmd)
            return  json.loads(out)
        except IOError as err:
            _dwarn("%s:%s" % (k, str(err)))
        except SSHException as err:
            _dwarn("%s:%s" % (k, str(err)))
        except ValueError as err:
            _dwarn("%s:unknow(%s)" % (k, err))
        except Exp, e:
            _dwarn("%s:%s" % (k, e.err))

        return []

    def __init__(self, config):
        self.config = config
        admin = os.path.join(self.config.lich, 'admin')
        self.node_script = os.path.join(admin, 'node.py')

        self.hosts = []
        for (k, v) in self.config.hosts.items():
            self.hosts.append(k)

    def __get_max(self, s, m):
        d = {}
        max_count = 0

        for i in s:
            count = m.count(i)
            #print("max %u %s --> %s" % (count, i, m))
            max_count = count  if (max_count < count) else max_count
            d[i] = count

        #print("max %u" % (max_count))
        for (k, v) in d.items():
            if (v == max_count):
                return k

    def __get_quorum(self):
        def __listnode_warp(host, lst):
            r = self.__listnode(host)
            lst.extend(r)

        lst = []
        args = [[x, lst] for x in self.hosts]
        mutil_exec(__listnode_warp, args, timeout = 5)

        metas = []
        for i in lst:
            m = i['metas']
            if (m):
                metas.append(self.__metas_clean(m))

        """
        l = ['Jack-pc/0', 'Jack-pc/1', 'Jack-pc/3', 'Jack-pc/2', 'Jack-pc/x']
        metas.append(_str(sorted(l)))
        return "Jack-pc/0,Jack-pc/1,Jack-pc/2,Jack-pc/3"
        """

        s = set(metas)
        #print("list:" + str(metas))
        #print("set:" + str(s))
        if (len(s) > 1):
            if (len(s) < 3):
                return self.__get_max(s, metas)
            else:
                _derror("bad quorum %s" % (metas))
                raise Exp(errno.EIO, 'bad quorum')
        else:
            return metas[0]

    def __metas_clean(self, m):
        if (m):
            if (m[-1] == ','):
                m1 =  m[:-1].split(',')
            else:
                m1 = m.split(',')

            return _str(sorted(m1))
        else:
            return None
        

    def __get_local_quorum(self):
        node  = Node()
        stat = node.stat_json()

        for i in range(len(stat)):
            stat[i]['metas'] = self.__metas_clean(stat[i]['metas'])

        return stat

    def __set_quorum(self, service, quorum):
        path = self.config.home + '/disk/' + str(service) + '/node/paxos/quorum'
        buf = "#version=0\n"
        q = quorum.split(',')
        for i in q:
            buf  += (i + "\n")

        print("set %s" % (path))
        print(buf)
        _set_value(path, buf)

    def check_quorum(self):
        """
        if (len(self.hosts) != 2):
            raise Exp(errno.ENOSYS, "not support")
        """
        quorum = self.__get_quorum()

        stat = self.__get_local_quorum()
        for i in stat:
            print("cmp:%s --> %s"  % (quorum, i['metas']))
            if (i['metas'] != quorum):
                _derror("bad quorum %s" % (i))
                self.__set_quorum(i['service'], quorum)

def main():
    config = Config()
    gemini = Gemini(config)
    gemini.check_quorum()

if __name__ == '__main__':
    main()
